package controller

import (
	"awesomeProject/lib"
	"bytes"
	"encoding/json"
	"github.com/sashabaranov/go-openai"
	"io"
	"log"
	"net/http"
)

var client = &http.Client{}
var xiaoMei = lib.UserBrief{
	Id:       10086,
	Username: "小美-你的智能助手",
	Gender:   0,
	Photo:    "",
}

// var autnToken = "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"
var conversation = make(map[int64][]openai.ChatCompletionMessage)

func StoreMsg(message *lib.Message, is_check bool) (string, error) {
	var time string
	var msgId int
	err := pool.QueryRow("insert into public.message(content, sender_id, receiver_id, sender_username, receiver_username, is_checked, time) values ($1, $2, $3, $4, $5, $6, $7) returning time, msg_id",
		message.Content,
		message.Sender.Id,
		message.Receiver.Id,
		message.Sender.Username,
		message.Receiver.Username,
		is_check,
		message.Time,
	).Scan(&time, &msgId)
	if len(message.Time) > 3 {
		time = message.Time
	}
	message.MsgId = msgId
	if err != nil {
		return time, err
	}
	return time, nil
}

func RedirectGpt(message lib.Message) error {
	Id := message.Sender.Id
	var chatContext []openai.ChatCompletionMessage
	chatContext, ok := conversation[Id]
	if !ok {
		conversation[Id] = chatContext
	}

	if message.Content == "#end" {
		GptMsgs := lib.Message{
			Sender:   xiaoMei,
			Receiver: message.Sender,
			Content:  "已结束本次对话，并清空上下文",
			Type:     "chat",
			Time:     message.Time,
			IsPhoto:  0,
		}
		log.Println("end:", GptMsgs)
		if err := Chat(&GptMsgs); err != nil {
			return err
		}
		delete(conversation, Id)
		return nil
	}
	chatContext = append(chatContext, openai.ChatCompletionMessage{
		Role:    openai.ChatMessageRoleUser,
		Name:    message.Sender.Username,
		Content: message.Content,
	})
	jsonLoad, err := json.Marshal(openai.ChatCompletionRequest{
		Model:    openai.GPT3Dot5Turbo,
		Messages: chatContext,
	})
	if err != nil {
		return err
	}
	log.Println(chatContext)
	req, err := http.NewRequest("POST", "https://openai.geekr.cool/v1/chat/completions", bytes.NewBuffer(jsonLoad))
	if err != nil {
		return err
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer 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")

	resp, err := client.Do(req)
	if err != nil {
		log.Println("do fail in client", err)
		return err
	}
	body, err := io.ReadAll(resp.Body)
	defer resp.Body.Close()
	var response openai.ChatCompletionResponse
	if err != nil {
		log.Println("get response from gpt api fail in chat", err)
		return err
	}
	if err := json.Unmarshal(body, &response); err != nil {
		return err
	}
	content := response.Choices[0].Message.Content
	log.Println(content + "test")
	chatContext = append(chatContext, openai.ChatCompletionMessage{
		Role:    openai.ChatMessageRoleAssistant,
		Content: content,
	})
	GptMsg := lib.Message{
		Sender:   xiaoMei,
		Receiver: message.Sender,
		Content:  content + "input #end to end this conversation",
		Type:     "chat",
		Time:     message.Time,
		IsPhoto:  0,
	}
	if err := Chat(&GptMsg); err != nil {
		return err
	}
	conversation[Id] = chatContext
	return nil
}

func PublicChat(content lib.Message) error {
	for id, conn := range clients {
		user, ok, err := SearchIdBrief(id)
		if !ok || err != nil {
			log.Println("get receiver fail")
			continue
		}
		if content.Sender.Id == id {
			continue
		}
		content.Sender.Id = 318030
		content.Receiver = user
		if err = conn.WriteJSON(content); err != nil {
			log.Println("write json fail to ", content.Receiver)
			continue
		}
	}
	return nil
}

func Chat(content *lib.Message) error {

	receiverId := content.Receiver.Id
	if receiverId == 10086 {
		if err := RedirectGpt(*content); err != nil {
			log.Println("redirect to gpt fail in chat", err)
		}
	}
	if receiverId == 318030 {
		if err := PublicChat(*content); err != nil {
			log.Println("public chat fail in chat", err)
		}
	}
	targetConn, ok := clients[receiverId]
	var time string
	var err error
	if !ok {
		log.Println("conv targetConn fail in ws")
		log.Println(content)
		log.Println("receiver: ", receiverId)

		time, err = StoreMsg(content, false)
		return err
	} else {
		time, err = StoreMsg(content, true)
	}
	if err != nil {
		log.Println("message write in database fail in chat", err)
	}
	content.Time = time
	if err := targetConn.WriteJSON(content); err != nil {
		log.Println("write in targetConn fail in ws", err)
		return err
	}
	return nil
}

func PullUncheckedMsg(id int64) (*[]lib.Message, int, error) {
	var ucMessages []lib.Message
	rows, err := pool.Query("update public.message set is_checked=true where receiver_id=$1 and is_checked=false returning content, sender_id, receiver_id, sender_username, receiver_username", id)
	if err != nil {
		log.Println("database fail, id invalid or no unchecked message")
		return &ucMessages, 0, err
	}
	cnt := 0
	for rows.Next() {
		var message lib.Message
		err := rows.Scan(
			&message.Content,
			&message.Sender.Id,
			&message.Receiver.Id,
			&message.Sender.Username,
			&message.Receiver.Username,
		)
		if err != nil {
			log.Println("conv to message fail in pull message")
			return &ucMessages, cnt, err
		}
		cnt++
		message.Sender.Photo, message.Receiver.Photo = "null", "null"
		message.Sender.Gender, message.Receiver.Gender = 2, 2
		ucMessages = append(ucMessages, message)
	}
	return &ucMessages, cnt, nil
}
